package org.linlinjava.litemall.web.controller;

import java.util.*;
import java.util.stream.Collectors;

import javax.validation.constraints.NotNull;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.lang.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.*;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.util.ResponseUtil.ListResponse;
import org.linlinjava.litemall.core.util.ResponseUtil.Response;
import org.linlinjava.litemall.core.validator.Order;
import org.linlinjava.litemall.core.validator.Sort;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.web.annotation.LogAnno;
import org.linlinjava.litemall.web.annotation.LoginShop;
import org.linlinjava.litemall.web.annotation.LoginUser;
import org.linlinjava.litemall.web.service.WebGoodsService;
import org.linlinjava.litemall.web.vo.*;
import org.linlinjava.litemall.web.vo.goods.CategoryListVO;
import org.linlinjava.litemall.web.vo.goods.PackageDetailRespVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.mysql.jdbc.StringUtils;

import static org.linlinjava.litemall.web.util.WebResponseCode.CATEGORY_L2_ID_ERROR;

/**
 * 网络产品控制器
 * 商品服务
 *
 * @author yliyun
 * @date 2022/09/14
 */
@Api(value="商品controller",tags={"商品操作接口"})
@RestController
@RequestMapping("/web/goods")
@Validated
public class WebGoodsController {

    /**
     * 商品服务
     */
    @Autowired
	private LitemallGoodsService goodsService;

	@Autowired
	private LumierePackageService lumierePackageService;

    /**
     * 目录服务
     */
    @Autowired
	private LitemallCategoryService categoryService;

    /**
     * 搜索历史记录服务
     */
    @Autowired
	private LitemallSearchHistoryService searchHistoryService;

    /**
     * litemall商品配件服务
     */
    @Autowired
	private LitemallGoodsAccessoryService litemallGoodsAccessoryService;
    /**
     * litemall商店商品服务
     */
    @Autowired
	private LitemallShopMerchandiseService litemallShopMerchandiseService;
    /**
     * litemall商品服务
     */
    @Autowired
	private LitemallMerchandiseService litemallMerchandiseService;

    /**
     * 网络产品服务
     */
    @Autowired
	private WebGoodsService webGoodsService;
    /**
     * 商品地区服务
     */
    @Autowired
	private LitemallGoodsRegionService goodsRegionService;
    /**
     * 店地区服务
     */
    @Autowired
	private LitemallShopRegionService shopRegionService;
    /**
     * 地区服务
     */
    @Autowired
	private LitemallRegionService regionService;


    @ApiOperation(value="商品详情")
	@GetMapping("detail")
	@LogAnno
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", response = GoodsDetailResponseVO.class)
	})

	public Response<GoodsDetailResponseVO> detail(@ApiParam(name="id",value="商品id",required=true) @NotNull Integer id,
												  @ApiParam(name="shopId",value="登录的店铺id",required=true) @LoginShop Integer shopId) {
		return webGoodsService.detail(shopId, id);
	}

    /**
     * 新细节
     *
     * @param id id
     * @return {@link Response}<{@link LlitemallGoodsDetailVO}>
     */
    @ApiOperation(value="修改后的商品详情")
	@GetMapping("newDetail")
	@LogAnno
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", response = GoodsDetailResponseVO.class)
	})
	public Response<LlitemallGoodsDetailVO> newDetail(@ApiParam(name="id",value="商品id",required=true) @NotNull Integer id,@LoginShop Integer shopId) {
		return webGoodsService.newDetail(id,shopId);
	}



	@ApiOperation(value="套餐详情")
	@GetMapping("package-detail")
	@LogAnno
	public Response<PackageDetailRespVO> packageDetail(@ApiParam(name="id",value="商品id",required=true) @NotNull Integer id, @LoginShop Integer shopId) {
		return webGoodsService.packageDetail(id,shopId);
	}


    /**
     * 类别l1
     *
     * @return {@link Object}
     */
    @ApiOperation(value="商品一级分类")
	@GetMapping("categoryL1")
	@LogAnno
	public Object categoryL1() {
		List<LitemallCategory> categories = categoryService.queryChannel();
		return ResponseUtil.okList(categories);
	}


    /**
     * 类别Metadata
     * 商品分类类目
     *
     * @param id 分类类目ID
     * @return 商品分类类目
     */
    @ApiOperation(value="商品分类")
	@GetMapping("category")
	@LogAnno
	@ApiImplicitParams(
			value = {
					@ApiImplicitParam(name="id",value="分类Id",dataType = "Integer"),
			}
	)
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", response = LitemallCategoryDetailVO.class),
	})
	public Object category(@NotNull Integer id) {
		LitemallCategory category = categoryService.findById(id);
		LitemallCategory parentCategory = category.getPid() == 0 ? category : categoryService.findById(category.getPid());
		List<LitemallCategory> children = categoryService.queryByPid(parentCategory.getId());
		return ResponseUtil.ok(new LitemallCategoryDetailVO(category, parentCategory, children));
	}

    /**
     * 列表
     * 根据条件搜素商品
     * <p>
     * 1. 这里的前五个参数都是可选的，甚至都是空
     * 2. 用户是可选登录，如果登录，则记录用户的搜索关键字
     *
     * @param categoryId 分类类目ID，可选
     * @param brandId    品牌商ID，可选
     * @param keyword    关键字，可选
     * @param isNew      是否新品，可选
     * @param isHot      是否热买，可选
     * @param userId     用户ID
     * @param page       分页页数
     * @param limit      分页大小
     * @param sort       排序方式，支持"add_time", "retail_price"或"name"
     * @param order      排序类型，顺序或者降序
     * @param shopId     商店id
     * @return 根据条件搜素的商品详情
     */
    @ApiOperation(value="通过商品分类查询商品列表")
	@GetMapping("list")
	@LogAnno
	@ApiImplicitParams(
			value = {
					@ApiImplicitParam(name="categoryId",value="分类Id",dataType = "Integer"),
					@ApiImplicitParam(name="brandId",value="品牌Id",dataType = "Integer"),
					@ApiImplicitParam(name="keyword",value="关键字",dataType = "String"),
					@ApiImplicitParam(name="isNew",value="是否是新品，0--否，1--是",dataType = "Integer"),
					@ApiImplicitParam(name="isHot",value="是否是热门商品，0--否，1--是",dataType = "Integer"),

			}
	)
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", response = GoodsVO.class)
	})
	public Response<ListResponse<GoodsVO>> list(
		@LoginShop @NotNull Integer shopId,
		 Integer categoryId,
		Integer brandId,
		String keyword,
		Boolean isNew,
		Boolean isHot,
		@LoginUser Integer userId,
		@RequestParam(defaultValue = "1",name = "第几页") Integer page,
		@RequestParam(defaultValue = "10000",name="一页几条数据") Integer limit,
		@Sort(accepts = {"add_time", "retail_price", "name"}) @RequestParam(defaultValue = "add_time",name = "排序字段") String sort,
		@Order @RequestParam(defaultValue = "desc",name = "排序方式，desc从小到大，asc从大到小") String order) {

		//添加到搜索历史
		if (userId != null && !StringUtils.isNullOrEmpty(keyword)) {
			LitemallSearchHistory searchHistoryVo = new LitemallSearchHistory();
			searchHistoryVo.setKeyword(keyword);
			searchHistoryVo.setUserId(userId);
			searchHistoryVo.setFrom("app");
			searchHistoryService.save(searchHistoryVo);
		}

		//查询列表数据
		List<GoodsVO> goodsVos = webGoodsService.list(shopId, categoryId, brandId, keyword, isHot, isNew, page, limit, sort, order);
		// 因为这里需要返回额外的filterCategoryList参数，因此不能方便使用ResponseUtil.okList
		return ResponseUtil.okList(goodsVos);
	}


    /**
     * 相关
     * 商品详情页面“大家都在看”推荐商品
     *
     * @param id id
     * @return 商品详情页面推荐商品
     */
    @ApiOperation(value="推荐商品")
	@GetMapping("related")
	@LogAnno
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", responseContainer = "List",response = LitemallGoodsVO.class)
	})
	public Object related(@ApiParam(name="id",value="商品id",required=true) @NotNull Integer id) {
		LitemallGoods goods = goodsService.findById(id);
		if (goods == null) {
			return ResponseUtil.badArgumentValue();
		}

		// 目前的商品推荐算法仅仅是推荐同类目的其他商品
		int cid = goods.getCategoryId();

		// 查找六个相关商品
		int related = 6;
		List<LitemallGoods> goodsList = goodsService.queryByCategory(cid, 0, related);
		List<LitemallGoodsVO> goodsVoList = new ArrayList<>();
		goodsList.stream().forEach(gs -> {
			LitemallGoodsVO vo = new LitemallGoodsVO();
			BeanUtils.copyProperties(gs,vo);
			goodsVoList.add(vo);
		});
		return ResponseUtil.okList(goodsVoList);
	}

    /**
     * 数
     * 在售的商品总数
     *
     * @param shopId 商店id
     * @return 在售的商品总数
     */
    @ApiOperation(value="在售商品总数")
	@GetMapping("count")
	@LogAnno
	@ApiResponses({
			@ApiResponse(code = 200, message = "返回门店中在售商品总数", response = Integer.class)
	})
	public Object count(@LoginShop @NotNull Integer shopId) {
		Integer goodsCount = goodsService.queryOnSaleByShop(shopId);
		return ResponseUtil.ok(goodsCount);
	}

    /**
     * 附件
     * 获取商品辅料
     *
     * @param goodsId 商品id
     * @param shopId  商店id
     * @return {@link Object}
     */
    @ApiOperation(value="商品辅料")
	@GetMapping("accessory")
	@LogAnno
	@ApiImplicitParams(
			value = {
					@ApiImplicitParam(name="shopId",value="门店Id,不用手动传入",dataType = "Integer"),
					@ApiImplicitParam(name="goodsId",value="商品Id",dataType = "Integer"),
			}
	)
	@ApiResponses({
			@ApiResponse(code = 200, message = "操作成功", responseContainer = "Map",response = AccessoryVO.class)
	})
	public Object accessory(@NotNull Integer goodsId, @LoginShop Integer shopId){
		List<LitemallGoodsAccessory> accessories = litemallGoodsAccessoryService.queryByGoodsId(goodsId);
//		LitemallGoods goods = goodsService.findById(goodsId);

		List<AccessoryVO> collect = accessories.stream().map(accessory -> {
			AccessoryVO vo = new AccessoryVO();
			BeanUtils.copyProperties(accessory, vo);
			LitemallMerchandise mer = litemallMerchandiseService.findById(accessory.getMerchandiseId());
			if (mer != null) {
				LitemallShopMerchandise shopMerchandise = litemallShopMerchandiseService.queryByMerIdAndShopId(mer.getId(), shopId);
				vo.setUnit(mer.getUnit());
				vo.setSelectNum(0);
				if (shopMerchandise != null) {
					vo.setNumber(shopMerchandise.getNumber());
				} else {
					vo.setNumber(0.00);
				}
			}
			return vo;
		}).collect(Collectors.toList());

		Map<String, List<AccessoryVO>> rtn = collect.stream().collect(Collectors.groupingBy(AccessoryVO::getGroupName));
		return ResponseUtil.ok(rtn);
	}

    /**
     * 货物清单l2
     *
     * @param categoryId 类别id
     * @param shopId     商店id
     * @return {@link Object}
     */
    @ApiOperation(value="通过商品分类查询商品列表")
	@GetMapping("listGoodsByL2")
	@LogAnno
	public Object listGoodsByL2(@NotNull Integer categoryId,@LoginShop Integer shopId){
		List<CategoryListVO> categoryList = new ArrayList<>();
 		LitemallCategory categoryL2 = categoryService.findById(categoryId);
		if(categoryL2 == null || !categoryL2.getLevel().equals(Constants.CATEGORY_LEVEL_L2)){return ResponseUtil.fail(CATEGORY_L2_ID_ERROR,"二级类目id错误");}

		//店铺商品列表（查询跟店铺同一地区的总部商品和店铺商品）
		List<Integer> goodsIds = CollStreamUtil.toList(getShopGoodsIds(shopId), goodsRegion->goodsRegion.getGoodsId());

		//店铺套餐列表
		List<Integer> packageIds = CollStreamUtil.toList(getShopGoodsIds(shopId), goodsRegion->goodsRegion.getPackageId());

		//[{name:'类目',list:['商品|套餐']}] {purl:,name:'',isPackage:true}

		List<LitemallCategory> categoriesL3 = categoryService.queryByPid(categoryL2.getId());
		if(goodsIds.size()==0&&packageIds.size()==0){
			categoriesL3.forEach(item->categoryList.add(new CategoryListVO(item.getName(),CollUtil.newArrayList())));
			return ResponseUtil.ok(categoryList);
		}

		if(goodsIds.size()>0){
			//过滤不属于当前门店的商品
			List<LitemallGoods> filterGoodsList = goodsService.findByIds(goodsIds);
			//此方法直接修改原集合
			CollUtil.filter(filterGoodsList, (Filter<LitemallGoods>) goods ->  (goods.getShopId() == null || goods.getShopId() == shopId.intValue()) && goods.getIsOnSale());

			//三级菜单分组
			for (LitemallCategory category : categoriesL3) {
				List<LitemallGoods> goodsList = filterGoodsList.stream().filter(goods -> goods.getCategoryId().intValue() == category.getId()).collect(Collectors.toList());
				if(goodsList.size()==0)continue;
				List<CategoryListVO.CategoryObjListVO> categoryGoodsList = CollStreamUtil.toList(goodsList, convertedGoods -> new CategoryListVO.CategoryObjListVO(convertedGoods.getId(), convertedGoods.getName(), convertedGoods.getPicUrl(), false));
				categoryList.add(new CategoryListVO(category.getName(), categoryGoodsList));
			}
		}


		if(packageIds.size()>0){
			//过滤不属于当前门店的商品
			List<LumierePackage> filterPackageList = lumierePackageService.listByIds(packageIds);
			//此方法直接修改原集合
			CollUtil.filter(filterPackageList, (Filter<LumierePackage>) packageGoods ->  (packageGoods.getShopId() == null || packageGoods.getShopId() == shopId.intValue()) && packageGoods.getIsOnSale());

			//三级菜单分组
			for (LitemallCategory category : categoriesL3) {
				List<LumierePackage> packageList = filterPackageList.stream().filter(packageGoods -> packageGoods.getCategoryId().intValue() == category.getId()).collect(Collectors.toList());
				if(packageList.size()==0)continue;
				List<CategoryListVO.CategoryObjListVO> categoryPackageList = CollStreamUtil.toList(packageList,convertedPackage->new CategoryListVO.CategoryObjListVO(convertedPackage.getId(), convertedPackage.getPackageName(), convertedPackage.getPackageImg(), true));
				categoryList.add(new CategoryListVO(category.getName(),categoryPackageList));
			}
		}
		return ResponseUtil.ok(categoryList);
	}

	//获取门店商品Id集合
	public List<LitemallGoodsRegion> getShopGoodsIds(Integer shopId){
		if(shopId==null)return CollUtil.newArrayList();
		List<LitemallShopRegion> shopRegions = shopRegionService.queryByShopId(shopId);
		LitemallShopRegion shopRegionCity = shopRegions.get(shopRegions.size() - 1);
		return goodsRegionService.list(Wrappers.lambdaQuery(LitemallGoodsRegion.class).eq(LitemallGoodsRegion::getCityId, shopRegionCity.getRegionId()));
	}


    private Integer getShopRegionId(Integer shopId) {
		List<LitemallShopRegion> litemallShopRegions = shopRegionService.queryByShopId(shopId);
		if (!CollectionUtils.isEmpty(litemallShopRegions)) {
			for (LitemallShopRegion litemallShopRegion : litemallShopRegions) {
				LitemallRegion litemallRegion = regionService.findById(litemallShopRegion.getRegionId());
				if (Constants.REGION_TYPE_CITY.equals(litemallRegion.getType())) {
					return litemallShopRegion.getRegionId();
				}
			}
		}
		return null;
	}

}